﻿using System;
using System.Drawing;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using C4F.DevKit.Contacts.Data;
using System.Windows.Forms;

namespace C4F.DevKit.Contacts.Components
{
    [ToolboxItem(true), ToolboxBitmap(typeof(ContactsService))]
    public partial class ContactsService : Component
    {
        #region Private Data

        private ContactManager _mgr = new ContactManager();

        #endregion Private Data

        #region Constants

        private const string VCARD_EXTENSION = "vcf";
        private const string ALL_FILES_EXTENSION = "*";

        #endregion Constants

        #region Constructors

        /// <summary>
        /// Creates a new ContactService object.
        /// </summary>
        public ContactsService()
        {
            InitializeComponent();
            IsDesktopApplication = true;
        }

        /// <summary>
        /// Creates a new ContactService object with the container to add this component to.
        /// </summary>
        /// <param name="container">The container to add this component to.</param>
        public ContactsService(IContainer container)
        {
            container.Add(this);

            InitializeComponent();
            IsDesktopApplication = true;
        }

        #endregion Constructors

        #region Properties

        /// <summary>
        /// The file path to save vCards export by this object to. The value must also include the file name.
        /// </summary>
        public string vCardFilePath { get; set; }

        [Category("Contacts"), Browsable(true)]
        /// <summary>
        /// Determine if this component is being used in a desktop application
        /// </summary>        
        public bool IsDesktopApplication { get; set; }

        #endregion Properties

        #region Methods

        #region Public

        /// <summary>
        /// Removes a contact by the specified contact id.
        /// </summary>
        /// <param name="contactID">The ID of the contact to be removed.</param>
        public void RemoveContact(string contactID)
        {
            _mgr.Remove(contactID);
        }

        /// <summary>
        /// Retrieves all contacts.
        /// </summary>
        /// <returns>A collection of SimpleContactView objects.</returns>
        public List<SimpleContactView> GetAllSimpleContacts()
        {
            return new List<SimpleContactView>(_mgr.GetSimpleContactCollection());
        }

        /// <summary>
        /// Retireves the contact with the specified id.
        /// </summary>
        /// <param name="contactId">The id of the contact to retrieve.</param>
        /// <returns>A SimpleContactView object.</returns>
        public SimpleContactView GetSimpleContact(string contactId)
        {
            return _mgr.GetSimpleContact(contactId);
        }

        /// <summary>
        /// Retrieves all contacts.
        /// </summary>
        /// <returns>A collection of Contacts objects.</returns>
        public List<Contact> GetAllContacts()
        {
            return new List<Contact>(_mgr.GetContactCollection());
        }

        /// <summary>
        /// Retrieves the contact with the specified id.
        /// </summary>
        /// <param name="contactId">The id of the contact to retrieve.</param>
        /// <returns>A Contact object.</returns>
        public Contact GetContact(string contactId)
        {
            return _mgr.GetContact(contactId);
        }

        /// <summary>
        /// Saves the specified contact.
        /// </summary>
        /// <param name="simpleContact"></param>
        public void SaveContact(SimpleContactView simpleContact)
        {
            simpleContact.CommitChanges();
        }

        /// <summary>
        /// Saves the specified contact.
        /// </summary>
        /// <param name="theContact"></param>
        public void SaveContact(Contact theContact)
        {
            theContact.CommitChanges();
        }

        /// <summary>
        /// Gets a new contact as a SimpleContactView object
        /// </summary>
        /// <returns>A SimpleContactView object.</returns>
        public SimpleContactView GetNewSimpleContact()
        {
            return _mgr.CreateSimpleContact();
        }

        /// <summary>
        /// Performs a 'contains' search for the contacts matching the specified criteria parameters.
        /// </summary>
        /// <remarks>This method will search all Contacts data for the specified criteria.</remarks>
        /// <param name="fname">First name.</param>
        /// <param name="lname">Last name.</param>
        /// <param name="street">Street address.</param>
        /// <param name="city">City</param>
        /// <param name="state">State</param>
        /// <param name="country">Country</param>
        /// <returns>An IEnumerable of Contact objects.<returns>
        public IEnumerable<Contact> SearchContacts(string fname, string lname, string street, string city, string state, string country)
        {
            // First, get all contacts 
            var contacts = _mgr.GetContactCollection();

            // Search for the contacts which match the filter criteria.
            var t =
                from detail in contacts

                from name in detail.Names
                where name.GivenName.ToLower().Contains(fname.ToLower()) &&
                    name.FamilyName.ToLower().Contains(lname.ToLower())

                from addrs in detail.Addresses
                where (addrs.Street.ToLower().Contains(street.ToLower())) &&
                    (addrs.City.ToLower().Contains(city.ToLower())) &&
                    (addrs.State.ToString().ToLower().Contains(state.ToLower())) &&
                    (addrs.Country.ToLower().Contains(country.ToLower()))
                select detail;

            return t.Distinct();
        }

        /// <summary>
        /// Performs a 'contains' search for the contacts matching the specified criteria parameters.
        /// </summary>
        /// <remarks>his method will search all Contacts data for the specified criteria.</remarks>
        /// <param name="fname">First name.</param>
        /// <param name="lname">Last name.</param>
        /// <param name="street">Street address.</param>
        /// <param name="city">City</param>
        /// <param name="state">State</param>
        /// <param name="country">Country</param>
        /// <returns>A collection of SimpleContactView objects.</returns>
        public IEnumerable<SimpleContactView> SearchSimpleContacts(string fname, string lname, string street, string city, string state, string country)
        {
            // First, get all contacts 
            var contacts = _mgr.GetSimpleContactCollection();

            // Search for the contacts which match the filter criteria.
            var t =
                from detail in contacts
                where detail.FirstName.ToLower().Contains(fname.ToLower()) &&
                    detail.LastName.ToLower().Contains(lname.ToLower()) &&
                    detail.HomeStreet.ToLower().Contains(street.ToLower()) &&
                    detail.HomeCity.ToLower().Contains(city.ToLower()) &&
                    detail.HomeState.ToLower().Contains(state.ToLower()) &&
                    detail.HomeCountry.ToLower().Contains(country.ToLower()) &&
                    detail.BusinessStreet.ToLower().Contains(street.ToLower()) &&
                    detail.BusinessCity.ToLower().Contains(city.ToLower()) &&
                    detail.BusinessState.ToLower().Contains(state.ToLower()) &&
                    detail.BusinessCountry.ToLower().Contains(country.ToLower())
                select detail;

            return t.Distinct();
        }

        /// <summary>
        /// Exports a contact to a vCard file to the specified file path. The contact must already exist.
        /// </summary>
        /// <param name="contactID">The id of the contact to export.</param>
        /// <param name="filePath">The path to save the vCard file to. The path must also include the file name.</param>
        public bool ExportContactToVCard(string contactId, string filePath)
        {
            Contact contact = _mgr.GetContact(contactId);
            Contact.SaveToVCard21(contact, filePath);

            return true;
        }

        /// <summary>
        /// Exports a contact to a vCard file. The contact must already exist.
        /// </summary>
        /// <remarks>
        /// This method will export to the file path specified by the vCardFilePath property. If this is a desktop application and the 
        /// vCardFilePath property is not specified, a SaveFileDialog will be displayed in which the user may specify the file path.
        /// </remarks>
        /// <param name="contactID">The id of the contact to export.</param>        
        public bool ExportContactToVCard(string contactID)
        {
            string filePath = string.Empty;
            DialogResult saveDialogResult = DialogResult.None;

            if (!IsDesktopApplication && string.IsNullOrEmpty(vCardFilePath))
                throw new Exception("A file path is required when the application is not a desktop application.");

            if (!string.IsNullOrEmpty(vCardFilePath))
            {
                filePath = vCardFilePath;
            }
            else if (IsDesktopApplication && string.IsNullOrEmpty(vCardFilePath))
            {
                SaveFileDialog dlg = new SaveFileDialog();
                dlg.OverwritePrompt = true;
                dlg.AddExtension = true;
                dlg.DefaultExt = VCARD_EXTENSION;
                dlg.Filter = string.Format("vCard files  (*.{0})|*.{0}|All files(*.{1})|*.{1}", VCARD_EXTENSION, ALL_FILES_EXTENSION);

                saveDialogResult = dlg.ShowDialog();

                if (saveDialogResult == DialogResult.OK)
                    filePath = dlg.FileName;
                else
                    return false;
            }

            if (string.IsNullOrEmpty(filePath))
                throw new System.IO.IOException("No file path specified.");
            else
                return ExportContactToVCard(contactID, filePath);

        }

        /// <summary>
        /// Imports a contact from the specified file.
        /// </summary>
        /// <param name="filePath">The file to import the contact from.</param>
        public void ImportContactFromVCard(string filePath)
        {
            _mgr.ImportFromVCard(filePath);
        }

        /// <summary>
        /// Imports a contact. 
        /// </summary>
        /// <remarks>If the IsDesktopApplication is true, an OpenFileDialog will prompt the user for a file.</remarks>
        public void ImportContactFromVCard()
        {
            if (!IsDesktopApplication)
                throw new Exception("Please specify the file to be imported.");

            OpenFileDialog dlg = new OpenFileDialog();
            dlg.DefaultExt = VCARD_EXTENSION;
            dlg.Filter = string.Format("vCard files (*.{0})|*.{0}", VCARD_EXTENSION);

            if (dlg.ShowDialog() == DialogResult.OK)
                ImportContactFromVCard(dlg.FileName);
        }

        /// <summary>
        /// Exports a contact to a database.
        /// </summary>
        /// <param name="contactId">The id of the contact to exrport.</param>
        public void ExportContactToDatabase(string contactId)
        {
            SimpleContactDataProvider prvdr = new SimpleContactDataProvider();
            SimpleContactView simpleContact = _mgr.GetSimpleContact(_mgr.GetContact(contactId));

            prvdr.Save(simpleContact.ToDataset());
        }

        /// <summary>
        /// Imports the contact from a database with the specified id.
        /// </summary>
        /// <param name="contactId">The id of the contact to import.</param>
        public void ImportContactFromDatabase(Guid contactId)
        {
            _mgr.ImportContactFromDatabase((contactId));
        }

        /// <summary>
        /// Saves the specified contact to a vCard.
        /// </summary>
        /// <param name="theContact">The contact to save to the vCard file.</param>
        /// <param name="filePath">The path to save the vCard file to.</param>
        public void SaveContactToVCard(Contact theContact, string filePath)
        {
            Contact.SaveToVCard21(theContact, filePath);
        }

        /// <summary>
        /// Saves the specfieid contact to the specified file.
        /// </summary>
        /// <param name="simpleContact">The contact to save.</param>
        /// <param name="filePath">The file to save the contact to.</param>
        public void SaveContactToVCard(SimpleContactView simpleContact, string filePath)
        {
            simpleContact.SaveToVCard21(filePath);
        }

        /// <summary>
        /// Gets a SimpleContactDataSet populated with contacts.
        /// </summary>
        /// <returns>A SimpleContactDataSet object.</returns>
        public SimpleContactDataSet GetSimpleContactsFromDatabase()
        {
            return new SimpleContactDataProvider().Load();
        }

        #endregion Public

        #endregion Methods
    }
}
